const EventEmitter = require("events");
const { writeFile } = require("fs");
const inquirer = require("inquirer");
const { format } = require("path");
const Generator = require("./Generator");
const { installDeps } = require("./utils/installDeps");
const logInfo = require('../../util/logInfo');
const logStep = require('../../util/logStep');
const { defaultPreset } = require("./utils/options");
const PromptModuleAPI = require("./utils/PromptModuleAPI");
const writeFileTree = require("./utils/writeFileTree");
module.exports = class Creator extends EventEmitter {
  constructor(name, context, promptModules) {
    super();
    logStep("3.1 Creator -> constructor初始化参数");
    this.name = name;
    this.context = context;

    logStep("3.1.1 选择配置方式：缓存的prest配置 || 手动选择配置");
    this.presetPrompt = {
      name: "preset",
      type: "list",
      message: `Please pick a preset:`,
      choices: [
        {
          name: "Manually select features",
          value: "__manual__",
        },
        {
          name: "之前保存的配置",
          name: "saved",
        },
      ],
    };
    this.featurePrompt = {
      name: "features",
      // when: isManualMode,
      type: "checkbox",
      message: "Check the features needed for your project:",
      choices: [],
      pageSize: 10,
    };
    logStep("3.1.2 选择各种配置文件的存储方式： package.json | 各自的独立文件");
    logStep("3.1.3 选择是否保存配置");
    logStep("3.1.4 选择 npm 包管理方式： yarn | pnpm | npm ");
    this.outroPrompts = [
      {
        name: "useConfigFiles",
        // when: isManualMode, 判断上一步是否选中了手动
        type: "list",
        message:
          "Where do you prefer placing config for Babel, PostCSS, ESLint, etc.?",
        choices: [
          {
            name: "In dedicated config files",
            value: "files",
          },
          {
            name: "In package.json",
            value: "pkg",
          },
        ],
      },
    ]; //多个问题,其他省略

    this.injectedPrompts = [];
    this.promptCompleteCbs = []; //所有提问结果集
    this.createCompleteCbs = [];

    const promptApi = new PromptModuleAPI(this);
    logStep(
      "3.1.5 将 promptModules 中的配置询问注入到 cli 对应的 prompts 中 (PromptModuleAPI)"
    );
    promptModules.forEach((m) => m(promptApi));
  }

  async create(cliOptions = {}, preset = null) {
    logStep("3.2 create 分为两种方式: options 创建 和 preset 创建");
    if (!preset) {
      preset = await this.resolvePreset();
      if (!preset) {
        preset = await this.promptAndResolvePreset();
      }
    }

    logStep("3.2.3 preset 合并 cli-serve 的参数");
    preset.plugins["@vue/cli-service"] = Object.assign(
      {
        projectName: this.name,
      },
      preset
    );
    if (cliOptions.bare) {
      preset.plugins["@vue/cli-service"].bare = true;
    }

    this.emit("creation", { event: "creating" }); //事件钩子

    logStep("3.3 初始化 package.json 文件");
    const pkg = {
      name: this.name,
      version: "0.1.0",
      private: true,
      devDependencies: {},
    };
    const deps = Object.keys(preset.plugins);
    deps.forEach((dep) => {
      pkg.devDependencies[dep] = preset.plugins[dep].version || "latest";
    });
    logStep(
      "3.3.1 将选择的依赖注入到 packkage.json 文件中:" + deps.join(" | ")
    );
    await writeFileTree(this.context, {
      "package.json": JSON.stringify(pkg, null, 2),
    });

    logStep("3.4 判断是否需要初始化 git");

    logStep("3.5 安装依赖");
    const { stipInstall } = await inquirer.prompt([
      {
        name: "stipInstall",
        type: "list",
        message: "是否需要跳过安装步骤？",
        choices: [
          { name: "Yes", value: true },
          { name: "No", value: false },
        ],
      },
    ]);
    if (!stipInstall) {
      await installDeps(this.context, "npm");
    }
    logStep("4 构造项目");
    const plugins = await this.reslovePlugins(preset.plugins);
    const generator = new Generator(this.context, {
      pkg,
      plugins,
      completeCbs: this.createCompleteCbs,
    });
    await generator.generate();

    logStep(
      "5 安装完成后，有些插件需要在安装完成后再做一些操作，此处要做一次调用：createCompleteCbs"
    );
    this.emit("creation", { event: "completion-hooks" });
    for (const cb of this.createCompleteCbs) {
      await cb();
    }

    logStep("6 安装完成");
  }

  async reslovePlugins(rawPlugins) {
    console.log(rawPlugins);
    logStep(
      "4.1 加载插件,重新组装获取需要的值，返回值将作为参数传递给 generator 构造器"
    );
    logInfo("在加载插件时有一点特殊的时要保证 @vue/cli-service 在第一位");
    const plugins = [];
    logStep(
      "4.1.1 加载插件是，采用 require.resolve 方法加载上一步 install 到 node_moduels 中的插件"
    );
    for (const id of Object.keys(rawPlugins)) {
      const apply =
        require(require.resolve(id + "/generator", {
          paths: [this.context],
        })) || (() => {});
      let options = rawPlugins[id] || {};
      plugins.push({ id, apply, options });
    }
    return plugins;
  }

  async resolvePreset(name, clone) {
    logStep(
      `3.2.1 构建 preset (resolvePreset) : savedPreset / localPreset / remotePreset / defaultPreset`
    );
    return null;
  }

  async promptAndResolvePreset() {
    logStep("3.2.2 选择手动 preset");
    const prompts = [
      this.presetPrompt,
      this.featurePrompt,
      ...this.injectedPrompts,
      ...this.outroPrompts,
    ];
    const answers = await inquirer.prompt(prompts);
    logInfo(
      "结果中判断,如果选择了自动,则要再从自动中获取配置,如果选择了手动,则要再从手动中获取一下配置"
    );
    let preset = {
      useConfigFiles: answers.useConfigFiles === "files",
      plugins: {},
    };
    answers.features = answers.features || [];
    console.log(answers);
    // run cb registered by prompt modules to finalize the preset
    logStep(
      "3.2.3 promptCompleteCbs 根据各个插件自己的配置,合并选择结果到preset 中"
    );
    this.promptCompleteCbs.forEach((cb) => cb(answers, preset));
    logStep("3.2.4 validatePreset -> savePreset 验证并根据配置保存 preset");

    return preset;
  }
};
